<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id$

/**
 +------------------------------------------------------------------------------
 * Think 标准模式公共函数库
 +------------------------------------------------------------------------------
 * @category   Think
 * @package  Common
 * @author   liu21st <liu21st@gmail.com>
 * @version  $Id$
 +------------------------------------------------------------------------------
 */

// 错误输出
function halt($error) {
	$e = array();
	if (APP_DEBUG) {
		//调试模式下输出错误信息
		if (!is_array($error)) {
			$trace = debug_backtrace();
			$e['message'] = $error;
			$e['file'] = $trace[0]['file'];
			$e['class'] = $trace[0]['class'];
			$e['function'] = $trace[0]['function'];
			$e['line'] = $trace[0]['line'];
			$traceInfo = '';
			$time = date('y-m-d H:i:m');
			foreach ($trace as $t) {
				$traceInfo .= '[' . $time . '] ' . $t['file'] . ' (' . $t['line'] . ') ';
				$traceInfo .= $t['class'] . $t['type'] . $t['function'] . '(';
				$traceInfo .= implode(', ', $t['args']);
				$traceInfo .=')<br/>';
			}
			$e['trace'] = $traceInfo;
		} else {
			$e = $error;
		}
		// 包含异常页面模板
		include C('TMPL_EXCEPTION_FILE');
	} else {
		//否则定向到错误页面
		$error_page = C('ERROR_PAGE');
		if (!empty($error_page)) {
			redirect($error_page);
		} else {
			if (C('SHOW_ERROR_MSG'))
			$e['message'] = is_array($error) ? $error['message'] : $error;
			else
			$e['message'] = C('ERROR_MESSAGE');
			// 包含异常页面模板
			include C('TMPL_EXCEPTION_FILE');
		}
	}
	exit;
}

// 自定义异常处理
function throw_exception($msg, $type='ThinkException', $code=0) {
	if (class_exists($type, false))
	throw new $type($msg, $code, true);
	else
	halt($msg);        // 异常类型不存在则输出错误信息字串
}

// 浏览器友好的变量输出
function dump($var, $echo=true, $label=null, $strict=true) {
	$label = ($label === null) ? '' : rtrim($label) . ' ';
	if (!$strict) {
		if (ini_get('html_errors')) {
			$output = print_r($var, true);
			$output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
		} else {
			$output = $label . print_r($var, true);
		}
	} else {
		ob_start();
		var_dump($var);
		$output = ob_get_clean();
		if (!extension_loaded('xdebug')) {
			$output = preg_replace("/\]\=\>\n(\s+)/m", '] => ', $output);
			$output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
		}
	}
	if ($echo) {
		echo($output);
		return null;
	}else
	return $output;
}

// 区间调试开始
function debug_start($label='') {
	$GLOBALS[$label]['_beginTime'] = microtime(TRUE);
	if (MEMORY_LIMIT_ON)
	$GLOBALS[$label]['_beginMem'] = memory_get_usage();
}

// 区间调试结束，显示指定标记到当前位置的调试
function debug_end($label='') {
	$GLOBALS[$label]['_endTime'] = microtime(TRUE);
	echo '<div style="text-align:center;width:100%">Process ' . $label . ': Times ' . number_format($GLOBALS[$label]['_endTime'] - $GLOBALS[$label]['_beginTime'], 6) . 's ';
	if (MEMORY_LIMIT_ON) {
		$GLOBALS[$label]['_endMem'] = memory_get_usage();
		echo ' Memories ' . number_format(($GLOBALS[$label]['_endMem'] - $GLOBALS[$label]['_beginMem']) / 1024) . ' k';
	}
	echo '</div>';
}

// 添加和获取页面Trace记录
function trace($title='',$value='') {
	if(!C('SHOW_PAGE_TRACE')) return;
	static $_trace =  array();
	if(is_array($title)) { // 批量赋值
		$_trace   =  array_merge($_trace,$title);
	}elseif('' !== $value){ // 赋值
		$_trace[$title] = $value;
	}elseif('' !== $title){ // 取值
		return $_trace[$title];
	}else{ // 获取全部Trace数据
		return $_trace;
	}
}

// 设置当前页面的布局
function layout($layout) {
	if(false !== $layout) {
		// 开启布局
		C('LAYOUT_ON',true);
		if(is_string($layout)) {
			C('LAYOUT_NAME',$layout);
		}
	}
}

// URL组装 支持不同模式
// 格式：U('[分组/模块/操作]?参数','参数','伪静态后缀','是否跳转','显示域名')
function U($url,$vars='',$suffix=true,$redirect=false,$domain=false) {
	// 解析URL
	$info =  parse_url($url);
	$url   =  !empty($info['path'])?$info['path']:ACTION_NAME;
	// 解析子域名
	if($domain===true){
		$domain = $_SERVER['HTTP_HOST'];
		if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署
			$domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.');
			// '子域名'=>array('项目[/分组]');
			foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) {
				if(false === strpos($key,'*') && 0=== strpos($url,$rule[0])) {
					$domain = $key.strstr($domain,'.'); // 生成对应子域名
					$url   =  substr_replace($url,'',0,strlen($rule[0]));
					break;
				}
			}
		}
	}
	// 解析参数
	if(is_string($vars)) { // aaa=1&bbb=2 转换成数组
		parse_str($vars,$vars);
	}elseif(!is_array($vars)){
		$vars = array();
	}
	if(isset($info['query'])) { // 解析地址里面参数 合并到vars
		parse_str($info['query'],$params);
		$vars = array_merge($params,$vars);
	}

	// URL组装
	$depr = C('URL_PATHINFO_DEPR');
	if($url) {
		if(0=== strpos($url,'/')) {// 定义路由
			$route   =  true;
			$url   =  substr($url,1);
			if('/' != $depr) {
				$url   =  str_replace('/',$depr,$url);
			}
		}else{
			if('/' != $depr) { // 安全替换
				$url   =  str_replace('/',$depr,$url);
			}
			// 解析分组、模块和操作
			$url   =  trim($url,$depr);
			$path = explode($depr,$url);
			$var  =  array();
			$var[C('VAR_ACTION')] = !empty($path)?array_pop($path):ACTION_NAME;
			$var[C('VAR_MODULE')] = !empty($path)?array_pop($path):MODULE_NAME;
			if(C('URL_CASE_INSENSITIVE')) {
				$var[C('VAR_MODULE')] =  parse_name($var[C('VAR_MODULE')]);
			}
			if(C('APP_GROUP_LIST')) {
				if(!empty($path)) {
					$group   =  array_pop($path);
					$var[C('VAR_GROUP')]  =   $group;
				}else{
					if(GROUP_NAME != C('DEFAULT_GROUP')) {
						$var[C('VAR_GROUP')]  =   GROUP_NAME;
					}
				}
			}
		}
	}
	$flag=true;
	if(C('URL_MODEL') == 0) { // 普通模式URL转换
		$url   =__APP__.'?'.http_build_query($var);
		if(!empty($vars)) {
			$vars = http_build_query($vars);
			$url   .= '&'.$vars;
		}
		$flag=false;
	}
	/**/
	if(C('URL_MODEL') == 2){
		$routes = C('URL_ROUTE_RULES');

		$_url=array_merge(parseUrl($url),$vars);

		foreach ($routes as $rule=>$route){
			$_route=parseUrl(str_replace(':', '_',$route));
			if(url_compare($_url, $_route))break;
		}
		if(url_compare($_url, $_route)){
			foreach ($_route as $key=>$val){
				if($key=='m'||$key=='a')continue;
				$rule=preg_replace("/(\(\\\[\w]\+\))/",$_url[$key],$rule,1);
			}
			//去掉最后的"/"
			$url=__APP__.'/'.trim($rule,'/');
				
			$flag=false;
		}
	}

	if($flag){ // PATHINFO模式或者兼容URL模式
		if(isset($route)) {
			$url   =  __APP__.'/'.$url;
		}else{
			$url   =  __APP__.'/'.implode($depr,array_reverse($var));
		}
		if(!empty($vars)) { // 添加参数
			$vars = http_build_query($vars);
			$url .= $depr.str_replace(array('=','&'),$depr,$vars);
		}
		if($suffix) {
			$suffix   =  $suffix===true?C('URL_HTML_SUFFIX'):$suffix;
			if($suffix) {
				$url  .=  '.'.ltrim($suffix,'.');
			}
		}
	}
	//file_put_contents("out.txt",$url."\r\n",FILE_APPEND);
	if($domain) {
		$url   =  'http://'.$domain.$url;
	}else{
		$url   =  "http://".$_SERVER['SERVER_NAME'].($_SERVER['SERVER_PORT']==80?'':':'.$_SERVER['SERVER_PORT']).$url;
	}
	if($redirect) // 直接跳转URL
	redirect($url);
	else
	return $url;
}

// URL重定向
function redirect($url, $time=0, $msg='') {
	//多行URL地址支持
	$url = str_replace(array("\n", "\r"), '', $url);
	if (empty($msg))
	$msg = "系统将在{$time}秒之后自动跳转到{$url}！";
	if (!headers_sent()) {
		// redirect
		if (0 === $time) {
			header('Location: ' . $url);
		} else {
			header("refresh:{$time};url={$url}");
			echo($msg);
		}
		exit();
	} else {
		$str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
		if ($time != 0)
		$str .= $msg;
		exit($str);
	}
}

// 全局缓存设置和读取
function S($name, $value='', $expire=null, $type='',$options=null) {
	static $_cache = array();
	//取得缓存对象实例
	$cache = Cache::getInstance($type,$options);
	if ('' !== $value) {
		if (is_null($value)) {
			// 删除缓存
			$result = $cache->rm($name);
			if ($result)
			unset($_cache[$type . '_' . $name]);
			return $result;
		}else {
			// 缓存数据
			$cache->set($name, $value, $expire);
			$_cache[$type . '_' . $name] = $value;
		}
		return;
	}
	if (isset($_cache[$type . '_' . $name]))
	return $_cache[$type . '_' . $name];
	// 获取缓存数据
	$value = $cache->get($name);
	$_cache[$type . '_' . $name] = $value;
	return $value;
}

// 快速文件数据读取和保存 针对简单类型数据 字符串、数组
function F($name, $value='', $path=DATA_PATH) {
	static $_cache = array();
	$filename = $path . $name . '.php';
	if ('' !== $value) {
		if (is_null($value)) {
			// 删除缓存
			return unlink($filename);
		} else {
			// 缓存数据
			$dir = dirname($filename);
			// 目录不存在则创建
			if (!is_dir($dir))
			mkdir($dir);
			$_cache[$name] =   $value;
			return file_put_contents($filename, strip_whitespace("<?php\nreturn " . var_export($value, true) . ";\n?>"));
		}
	}
	if (isset($_cache[$name]))
	return $_cache[$name];
	// 获取缓存数据
	if (is_file($filename)) {
		$value = include $filename;
		$_cache[$name] = $value;
	} else {
		$value = false;
	}
	return $value;
}

// 取得对象实例 支持调用类的静态方法
function get_instance_of($name, $method='', $args=array()) {
	static $_instance = array();
	$identify = empty($args) ? $name . $method : $name . $method . to_guid_string($args);
	if (!isset($_instance[$identify])) {
		if (class_exists($name)) {
			$o = new $name();
			if (method_exists($o, $method)) {
				if (!empty($args)) {
					$_instance[$identify] = call_user_func_array(array(&$o, $method), $args);
				} else {
					$_instance[$identify] = $o->$method();
				}
			}
			else
			$_instance[$identify] = $o;
		}
		else
		halt(L('_CLASS_NOT_EXIST_') . ':' . $name);
	}
	return $_instance[$identify];
}

// 根据PHP各种类型变量生成唯一标识号
function to_guid_string($mix) {
	if (is_object($mix) && function_exists('spl_object_hash')) {
		return spl_object_hash($mix);
	} elseif (is_resource($mix)) {
		$mix = get_resource_type($mix) . strval($mix);
	} else {
		$mix = serialize($mix);
	}
	return md5($mix);
}

// xml编码
function xml_encode($data, $encoding='utf-8', $root='think') {
	$xml = '<?xml version="1.0" encoding="' . $encoding . '"?>';
	$xml.= '<' . $root . '>';
	$xml.= data_to_xml($data);
	$xml.= '</' . $root . '>';
	return $xml;
}

function data_to_xml($data) {
	$xml = '';
	foreach ($data as $key => $val) {
		is_numeric($key) && $key = "item id=\"$key\"";
		$xml.="<$key>";
		$xml.= ( is_array($val) || is_object($val)) ? data_to_xml($val) : $val;
		list($key, ) = explode(' ', $key);
		$xml.="</$key>";
	}
	return $xml;
}

// session管理函数
function session($name,$value='') {
	$prefix   =  C('SESSION_PREFIX');
	if(is_array($name)) { // session初始化 在session_start 之前调用
		if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']);
		if(isset($_REQUEST[C('VAR_SESSION_ID')])){
			session_id($_REQUEST[C('VAR_SESSION_ID')]);
		}elseif(isset($name['id'])) {
			session_id($name['id']);
		}
		ini_set('session.auto_start', 0);
		if(isset($name['name'])) session_name($name['name']);
		if(isset($name['path'])) session_save_path($name['path']);
		if(isset($name['domain'])) ini_set('session.cookie_domain', $name['domain']);
		if(isset($name['expire'])) ini_set('session.gc_maxlifetime', $name['expire']);
		if(isset($name['use_trans_sid'])) ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0);
		if(isset($name['use_cookies'])) ini_set('session.use_cookies', $name['use_cookies']?1:0);
		if(isset($name['type'])) C('SESSION_TYPE',$name['type']);
		if(C('SESSION_TYPE')) { // 读取session驱动
			$class = 'Session'. ucwords(strtolower(C('SESSION_TYPE')));
			// 检查驱动类
			if(require_cache(EXTEND_PATH.'Driver/Session/'.$class.'.class.php')) {
				$hander = new $class();
				$hander->execute();
			}else {
				// 类没有定义
				throw_exception(L('_CLASS_NOT_EXIST_').': ' . $class);
			}
		}
		// 启动session
		if(C('SESSION_AUTO_START'))  session_start();
	}elseif('' === $value){
		if(0===strpos($name,'[')) { // session 操作
			if('[pause]'==$name){ // 暂停session
				session_write_close();
			}elseif('[start]'==$name){ // 启动session
				session_start();
			}elseif('[destroy]'==$name){ // 销毁session
				$_SESSION =  array();
				session_unset();
				session_destroy();
			}elseif('[regenerate]'==$name){ // 重新生成id
				session_regenerate_id();
			}
		}elseif(0===strpos($name,'?')){ // 检查session
			$name   =  substr($name,1);
			if($prefix) {
				return isset($_SESSION[$prefix][$name]);
			}else{
				return isset($_SESSION[$name]);
			}
		}elseif(is_null($name)){ // 清空session
			if($prefix) {
				unset($_SESSION[$prefix]);
			}else{
				$_SESSION = array();
			}
		}elseif($prefix){ // 获取session
			return $_SESSION[$prefix][$name];
		}else{
			return $_SESSION[$name];
		}
	}elseif(is_null($value)){ // 删除session
		if($prefix){
			unset($_SESSION[$prefix][$name]);
		}else{
			unset($_SESSION[$name]);
		}
	}else{ // 设置session
		if($prefix){
			if (!is_array($_SESSION[$prefix])) {
				$_SESSION[$prefix] = array();
			}
			$_SESSION[$prefix][$name]   =  $value;
		}else{
			$_SESSION[$name]  =  $value;
		}
	}
}

// Cookie 设置、获取、删除
function cookie($name, $value='', $option=null) {
	// 默认设置
	$config = array(
        'prefix' => C('COOKIE_PREFIX'), // cookie 名称前缀
        'expire' => C('COOKIE_EXPIRE'), // cookie 保存时间
        'path' => C('COOKIE_PATH'), // cookie 保存路径
        'domain' => C('COOKIE_DOMAIN'), // cookie 有效域名
	);
	// 参数设置(会覆盖黙认设置)
	if (!empty($option)) {
		if (is_numeric($option))
		$option = array('expire' => $option);
		elseif (is_string($option))
		parse_str($option, $option);
		$config = array_merge($config, array_change_key_case($option));
	}
	// 清除指定前缀的所有cookie
	if (is_null($name)) {
		if (empty($_COOKIE))
		return;
		// 要删除的cookie前缀，不指定则删除config设置的指定前缀
		$prefix = empty($value) ? $config['prefix'] : $value;
		if (!empty($prefix)) {// 如果前缀为空字符串将不作处理直接返回
			foreach ($_COOKIE as $key => $val) {
				if (0 === stripos($key, $prefix)) {
					setcookie($key, '', time() - 3600, $config['path'], $config['domain']);
					unset($_COOKIE[$key]);
				}
			}
		}
		return;
	}
	$name = $config['prefix'] . $name;
	if ('' === $value) {
		return isset($_COOKIE[$name]) ? $_COOKIE[$name] : null; // 获取指定Cookie
	} else {
		if (is_null($value)) {
			setcookie($name, '', time() - 3600, $config['path'], $config['domain']);
			unset($_COOKIE[$name]); // 删除指定cookie
		} else {
			// 设置cookie
			$expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;
			setcookie($name, $value, $expire, $config['path'], $config['domain']);
			$_COOKIE[$name] = $value;
		}
	}
}

// 加载扩展配置文件
function load_ext_file() {
	// 加载自定义外部文件
	if(C('LOAD_EXT_FILE')) {
		$files =  explode(',',C('LOAD_EXT_FILE'));
		foreach ($files as $file){
			$file   = COMMON_PATH.$file.'.php';
			if(is_file($file)) include $file;
		}
	}
	// 加载自定义的动态配置文件
	if(C('LOAD_EXT_CONFIG')) {
		$configs =  C('LOAD_EXT_CONFIG');
		if(is_string($configs)) $configs =  explode(',',$configs);
		foreach ($configs as $key=>$config){
			$file   = CONF_PATH.$config.'.php';
			if(is_file($file)) {
				is_numeric($key)?C(include $file):C($key,include $file);
			}
		}
	}
}

// 获取客户端IP地址
function get_client_ip() {
	static $ip = NULL;
	if ($ip !== NULL) return $ip;
	if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
		$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
		$pos =  array_search('unknown',$arr);
		if(false !== $pos) unset($arr[$pos]);
		$ip   =  trim($arr[0]);
	}elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
		$ip = $_SERVER['HTTP_CLIENT_IP'];
	}elseif (isset($_SERVER['REMOTE_ADDR'])) {
		$ip = $_SERVER['REMOTE_ADDR'];
	}
	// IP地址合法验证
	$ip = (false !== ip2long($ip)) ? $ip : '0.0.0.0';
	return $ip;
}

function send_http_status($code) {
	static $_status = array(
	// Success 2xx
	200 => 'OK',
	// Redirection 3xx
	301 => 'Moved Permanently',
	302 => 'Moved Temporarily ',  // 1.1
	// Client Error 4xx
	400 => 'Bad Request',
	403 => 'Forbidden',
	404 => 'Not Found',
	// Server Error 5xx
	500 => 'Internal Server Error',
	503 => 'Service Unavailable',
	);
	if(isset($_status[$code])) {
		header('HTTP/1.1 '.$code.' '.$_status[$code]);
		// 确保FastCGI模式下正常
		header('Status:'.$code.' '.$_status[$code]);
	}
}
function url_compare($url,$route){
	ksort($url);
	$url_keys=array_keys($url);
	ksort($route);
	$route_keys=array_keys($route);

	if($url['a']!=$route['a']||$url['m']!=$route['m']||$url_keys!=$route_keys){
		return false;
	}
	else{
		return true;
	}
}
function parseUrl($url) {
	$var  =  array();
	if(false !== strpos($url,'?')) { // [分组/模块/操作?]参数1=值1&参数2=值2...
		$info   =  parse_url($url);
		$path = explode('/',$info['path']);
		parse_str($info['query'],$var);
	}elseif(strpos($url,'/')){ // [分组/模块/操作]
		$path = explode('/',$url);
	}else{ // 参数1=值1&参数2=值2...
		parse_str($url,$var);
	}
	if(isset($path)) {
		$var[C('VAR_ACTION')] = array_pop($path);
		if(!empty($path)) {
			$var[C('VAR_MODULE')] = array_pop($path);
		}
		if(!empty($path)) {
			$var[C('VAR_GROUP')]  = array_pop($path);
		}
	}
	return $var;
}